#ifndef __MEMORY_H__
#define __MEMORY_H__

#include "base/Entity.h"
#include "base/LoadRequest.h"
#include "base/Request.h"
#include "base/Response.h"
#include "base/StoreRequest.h"
#include "util/List.h"
#include "util/Pool.h"

typedef struct {
    Time alarm;
    DataRequest* request;
} TimedRequest;

// constant because "ideal" system is only one that uses reservations in Memory
static const int reservationGranularity = 8;

class Memory : public Entity {
  public:
    NEW_DELETE_OPERATORS_H(Memory,Entity);
    Memory (const char* name, uint latency);
    ~Memory ();

    void tick ();
    uint getLatency () { return latency; }

    static void copyMemory (uint32* dest,
                            const uint32* src,
                            uint size,
                            LineMask const & mask,
                            bool tester);
    static bool cmpMemory (uint32* dest,
                           const uint32* src,
                           uint size,
                           LineMask const & mask,
                           bool tester);

  private:
    uint latency;
    List<TimedRequest*>* requests;
    List<Response*>* responses;

    Logger* memoryLog;

    virtual Result sinkFailed (Request* req, Response* resp, Result res);

    Result handle_DataRequest (Packet* r);
    Result handle_reservations (DataRequest* r);
    Result handle_RawFlushRequest (Packet* r);
    Result handle_QuiesceRequest (Packet* r); 
    Result handle_RawMemoryRequest (Packet* r);
    void enqueueDataRequest (DataRequest* dr);
    Response* makeResponse (DataRequest* r);

    void performOperation (DataRequest* r);
    // reservations
    int numReservations;
    bool* reserve;
    PA* reserve_addr;

};

/*
  We mask by the blocksize because we are doing
  reservations by cache block and not by word.
*/
#define CONVERT_TO_RESERVATION_GRANULE(_x) (ADDR_UINT32(_x) & ~(reservationGranularity - 1))

#endif // __MEMORY_H__
